package cn.bby.tools.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;

import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description: H
 * @author: bby
 * @date: 2025/11/7 17:55
 * @version: 1.0
 */
public class TemplateGenHelper {
    public enum GenFileEnum {
        CONTEXT("context", "Context", GenFileType.CONTEXT),
        PROCESS_TEMPLATE("", "ProcessTemplate", GenFileType.Template),
        PRE_VALIDATE("prevalidate", "PreValidate", GenFileType.NODE),
        DO_VALIDATE("dovalidate", "DoValidate", GenFileType.NODE),
        PRE_PROCESS("preprocess", "PreProcess", GenFileType.NODE),
        DO_PROCESS("doprocess", "DoProcess", GenFileType.NODE),
        POST_PROCESS("postprocess", "PostProcess", GenFileType.NODE),
        ;
        public final String pkgName;
        public final String name;
        public final GenFileType type;

        GenFileEnum(String pkgName, String name, GenFileType type) {
            this.pkgName = pkgName;
            this.name = name;
            this.type = type;
        }

        public final static Map<String, GenFileEnum> nameMap = Arrays.stream(values())
                .collect(Collectors.toMap(e -> e.name, e -> e));

    }
    public enum GenFileType {
        CONTEXT,
        NODE,
        Template;
    }
    /**
     * 生成模板
     *
     * @param projectDir   项目目录
     * @param savePkg      模板报错包路径
     * @param templateName 模板名称
     * @param files        要生成的文件列表
     * @param userName     用户名
     * @param overWrite    是否覆盖已有代码
     * @param note         注释
     * @return
     */
    public static String doGen(String projectDir, String savePkg, String templateName, List<GenFileEnum> files, String userName,
                               boolean overWrite, String note) {
        StringBuilder out = new StringBuilder();
        String date = DatePattern.NORM_DATETIME_FORMAT.format(new DateTime());
        String contextStr = contextData.replace("#{pkg}", savePkg)
                .replace("#{user}", userName)
                .replace("#{tempName}", templateName)
                .replace("#{note}", note)
                .replace("#{date}", date);
        String nodeStr = nodeData.replace("#{pkg}", savePkg)
                .replace("#{user}", userName)
                .replace("#{tempName}", templateName)
                .replace("#{note}", note)
                .replace("#{date}", date);
        String processTempStr = processTempData.replace("#{pkg}", savePkg)
                .replace("#{tempName}", templateName)
                .replace("#{user}", userName)
                .replace("#{note}", note)
                .replace("#{date}", date);
        if (!projectDir.endsWith("/")) {
            projectDir += "/";
        }
        String savePath = projectDir + "src/main/java/" + savePkg.replace(".", "/");
        File file = new File(savePath);
        FileUtil.mkdir(file);
        if (files.contains(GenFileEnum.CONTEXT)) {
            File contextFile = new File(savePath + "/context/" + templateName + GenFileEnum.CONTEXT.name + ".java");
            if (overWrite || !contextFile.exists()) {
                FileUtil.mkdir(contextFile.getParentFile());
                FileUtil.writeUtf8String(contextStr, contextFile);
                out.append('\n').append(contextFile.getAbsolutePath()).append(" 已生成");
            } else {
                out.append('\n').append(contextFile.getAbsolutePath()).append(" 已存在");
            }
        }
        if (files.contains(GenFileEnum.PROCESS_TEMPLATE)) {
            File templateFile = new File(savePath + "/" + templateName + GenFileEnum.PROCESS_TEMPLATE.name + ".java");
            if (overWrite || !templateFile.exists()) {
                FileUtil.mkdir(templateFile.getParentFile());
                FileUtil.writeUtf8String(processTempStr, templateFile);
                out.append('\n').append(templateFile.getAbsolutePath()).append(" 已生成");
            } else {
                out.append('\n').append(templateFile.getAbsolutePath()).append(" 已存在");
            }
        }
        StringBuilder ymlStr = new StringBuilder(300);
        ymlStr.append(templateName).append("ProcessTemplate:");
        if (StrUtil.isNotBlank(note)) {
            ymlStr.append(" #").append(note);
        }
        ymlStr.append("\n");
        for (GenFileEnum node : files) {
            if (node.type != GenFileType.NODE) {
                continue;
            }
            String className = templateName + node.name + "Cmp";
            File nodeFile = new File(savePath + "/" + node.pkgName + "/" + className + ".java");
            if (overWrite || !nodeFile.exists()) {
                FileUtil.mkdir(nodeFile.getParentFile());
                FileUtil.writeUtf8String(nodeStr.replace("#{ClassName}", className).replace("#{nodePkgName}", node.pkgName), nodeFile);
                out.append('\n').append(nodeFile.getAbsolutePath() + " 已生成");
            }
            ymlStr.append("  ").append(StrUtil.lowerFirst(node.name)).append(":\n");
            ymlStr.append("  - ").append(StrUtil.lowerFirst(className)).append("\n");
        }
        out.append('\n').append("yml：\n" + ymlStr);
        //复制到粘贴板
        StringSelection stringSelection = new StringSelection(ymlStr.toString());
        java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);

        out.append('\n').append("yml已复制到剪切板:")
                .append(ymlStr);
        return out.toString();
    }

    private static final String processTempData = """
            package #{pkg};
            
            import com.cmit.ctos.common.biz.core.AbstractProcessTemplate;
            import com.cmit.ctos.common.biz.core.RuleChainExecutor;
            import #{pkg}.context.#{tempName}Context;
            import lombok.extern.slf4j.Slf4j;
            import org.springframework.stereotype.Component;
            
            /**
             * #{note}
             * @author: #{user}
             * @date: #{date}
             */
            @Slf4j
            @Component
            public class #{tempName}ProcessTemplate extends AbstractProcessTemplate<#{tempName}Context> {
            
                public #{tempName}ProcessTemplate(RuleChainExecutor ruleChainExecutor) {
                    super.setRuleChainExecutor(ruleChainExecutor);
                    //规则链编码前缀
                    super.setChainCodePrefix(this.getClass().getSimpleName());
                }
            }
            """;
    private static final String contextData = """
            package #{pkg}.context;
            
            import com.cmit.ctos.common.biz.dto.ProcessDataDTO;
            import lombok.Data;
            import lombok.EqualsAndHashCode;
            import lombok.experimental.Accessors;
            
            /**
             * #{note}
             * @author: #{user}
             * @date: #{date}
             */
            @Data
            @Accessors(chain = true)
            @EqualsAndHashCode(callSuper = true)
            public class #{tempName}Context extends ProcessDataDTO {
            
            }
            
            """;
    private static final String nodeData = """
            package #{pkg}.#{nodePkgName};
            
            import com.cmit.ctos.common.biz.core.AbstractNode;
            import com.cmit.ctos.common.biz.dto.ProcessContext;
            import com.cmit.ctos.common.biz.dto.ProcessResponse;
            import #{pkg}.context.#{tempName}Context;
            import lombok.RequiredArgsConstructor;
            import lombok.extern.slf4j.Slf4j;
            import org.springframework.stereotype.Component;
            
            /**
             * #{note}
             * @author: #{user}
             * @date: #{date}
             */
            @Slf4j
            @Component
            @RequiredArgsConstructor
            public class #{ClassName} extends AbstractNode<#{tempName}Context> {
                @Override
                public ProcessResponse process(ProcessContext<#{tempName}Context> processContext) {
                    #{tempName}Context context = processContext.getProcessContext();
                    // todo: 待实现
                    return ProcessResponse.success(processContext.getChainCode());
                }
            }
            """;

}
